package com.vvv.designpattern.ordermanagement.statemachine;

import com.vvv.designpattern.ordermanagement.state.OrderState;
import com.vvv.designpattern.ordermanagement.state.OrderStateChangeAction;
import org.aspectj.apache.bcel.Repository;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.statemachine.config.EnableStateMachine;
import org.springframework.statemachine.config.StateMachineConfigurerAdapter;
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
import org.springframework.statemachine.persist.RepositoryStateMachinePersist;
import org.springframework.statemachine.redis.RedisStateMachineContextRepository;
import org.springframework.statemachine.redis.RedisStateMachinePersister;

import java.util.EnumSet;

/**
 * @author vvv
 * @date 2023-11-21 11 18
 * discription
 */
@Configuration
@EnableStateMachine(name="orderStateMachine")
public class OrderStateMachineConfig extends StateMachineConfigurerAdapter<OrderState, OrderStateChangeAction> {

    /**
     * 订单初始化状态配置
     * @param states
     * @throws Exception
     */
    @Override
    public void configure(StateMachineStateConfigurer<OrderState, OrderStateChangeAction> states) throws Exception {
        states.withStates()
                // 订单创建成功后的初始状态为ORDER_WAIT_PAY
                .initial(OrderState.ORDER_WAIT_PAY)
                // OrderState中所有的状态，加载配置到状态机中
                .states(EnumSet.allOf(OrderState.class));
    }

    /**
     * 订单状态转换流程配置
     * @param transitions
     * @throws Exception
     */
    @Override
    public void configure(StateMachineTransitionConfigurer<OrderState, OrderStateChangeAction> transitions) throws Exception {
        /**
         * source 当前的订单状态
         * target 要转化为的订单状态
         * event 需要执行的操作
         */
        transitions.withExternal()
                // 订单从 ORDER_WAIT_PAY 状态转换成 ORDER_WAIT_SEND 状态，需要 PAY_ORDER 操作
                .source(OrderState.ORDER_WAIT_PAY)
                .target(OrderState.ORDER_WAIT_SEND)
                .event(OrderStateChangeAction.PAY_ORDER)
                .and()
                // 订单从 ORDER_WAIT_SEND 状态转换成 ORDER_WAIT_RECEIVE 状态，需要 SEND_ORDER 操作
                .withExternal()
                .source(OrderState.ORDER_WAIT_SEND)
                .target(OrderState.ORDER_WAIT_RECEIVE)
                .event(OrderStateChangeAction.SEND_ORDER)
                .and()
                // 订单从 ORDER_WAIT_RECEIVE 状态转换成 ORDER_FINISH 状态，需要 RECEIVE_ORDER 操作
                .withExternal()
                .source(OrderState.ORDER_WAIT_RECEIVE)
                .target(OrderState.ORDER_FINISH)
                .event(OrderStateChangeAction.RECEIVE_ORDER);
    }

    /**
     * 该 bean 用于将状态机的状态信息存储到 Redis 中
     * @param redisConnectionFactory
     * @return
     */
    @Bean(name = "stateMachineRedisPersister")
    public RedisStateMachinePersister<OrderState, OrderStateChangeAction> getRedisPersister(
            RedisConnectionFactory redisConnectionFactory
    ) {
        // 1. 创建 RedisStateMachineContextRepository，用于将状态机上下文存储到 Redis 中
        RedisStateMachineContextRepository<OrderState, OrderStateChangeAction> repository =
                new RedisStateMachineContextRepository<>(redisConnectionFactory);

        // 2. 创建 RepositoryStateMachinePersist，它是 DAO 层的封装，将状态机的状态信息存储到上述的 repository 中
        RepositoryStateMachinePersist<OrderState, OrderStateChangeAction> persist =
                new RepositoryStateMachinePersist<>(repository);

        // 3. 创建 RedisStateMachinePersister，它是状态机持久化的工具类，暴露给使用者，用于存储和恢复状态机的状态
        return new RedisStateMachinePersister<>(persist);
    }
}
